﻿/*
===========================================================================

  Copyright (c) 2010-2014 Darkstar Dev Teams

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see http://www.gnu.org/licenses/

  This file is part of DarkStar-server source code.

===========================================================================
*/

#include "../common/showmsg.h"

#include <time.h>
#include <sys/timeb.h>

#include "vana_time.h"
#include "utils/zoneutils.h"

CVanaTime* CVanaTime::_instance = NULL;

CVanaTime::CVanaTime()
{
	setCustomOffset(0);
    lastConquestUpdate = 0;
	lastWeatherUpdate = 0;
	lastVHourlyUpdate = 0;
	lastVDailyUpdate = 0;
}

/************************************************************************
*                                                                       *
*  Return current Vana'diel time                                        *
*                                                                       *
************************************************************************/

CVanaTime* CVanaTime::getInstance()
{
	if(_instance == NULL)
	{
		_instance = new CVanaTime();
	}
	return _instance;
}

/************************************************************************
*                                                                       *
*  Return current Vana'diel date                                        *
*                                                                       *
************************************************************************/

uint32 CVanaTime::getDate()
{
	return m_vanaDate;
}

/************************************************************************
*                                                                       *
*  Return current Vana'diel year                                        *
*                                                                       *
************************************************************************/

uint32 CVanaTime::getYear()
{
	return m_vYear;
}

/************************************************************************
*                                                                       *
*  Return current Vana'diel month                                       *
*                                                                       *
************************************************************************/

uint32 CVanaTime::getMonth()
{
	return m_vMon;
}

/************************************************************************
*                                                                       *
*  Return current Vana'diel day                                         *
*                                                                       *
************************************************************************/

uint32 CVanaTime::getDayOfTheMonth()
{
	return m_vDate;
}

/************************************************************************
*                                                                       *
*  Return current Vana'diel hour                                        *
*                                                                       *
************************************************************************/

uint32 CVanaTime::getHour()
{
	return m_vHour;
}

/************************************************************************
*                                                                       *
*  Return current Vana'diel minute                                      *
*                                                                       *
************************************************************************/

uint32 CVanaTime::getMinute()
{
	return m_vMin;
}

/************************************************************************
*                                                                       *
*  Return current Vana'diel day of the week                             *
*                                                                       *
************************************************************************/

uint32 CVanaTime::getWeekday()
{
	return m_vDay;
}

/************************************************************************
*                                                                       *
*  Return current real time                                             *
*                                                                       *
************************************************************************/

uint32 CVanaTime::getSysTime()
{
	return (uint32)(time(NULL) + m_customOffset * 2.4f);
}

/************************************************************************
*                                                                       *
*  Return current real hour                                             *
*                                                                       *
************************************************************************/

uint32 CVanaTime::getSysHour()
{
	time_t now = time(0);
	tm *ltm = localtime(&now);

	return ltm->tm_hour;
}

/************************************************************************
*                                                                       *
*  Return current real minute                                           *
*                                                                       *
************************************************************************/

uint32 CVanaTime::getSysMinute()
{
	time_t now = time(0);
	tm *ltm = localtime(&now);

	return ltm->tm_min;
}

/************************************************************************
*                                                                       *
*  Return current real second                                           *
*                                                                       *
************************************************************************/

uint32 CVanaTime::getSysSecond()
{
	time_t now = time(0);
	tm *ltm = localtime(&now);

	return ltm->tm_sec;
}

/************************************************************************
*                                                                       *
*  Return current real day of the week                                  *
*                                                                       *
************************************************************************/

uint32 CVanaTime::getSysWeekDay()
{
	time_t now = time(0);
	tm *ltm = localtime(&now);

	return ltm->tm_wday;
}

/************************************************************************
*                                                                       *
*  Return current real year and day                                     *
*                                                                       *
************************************************************************/

uint32 CVanaTime::getSysYearDay()
{
	time_t now = time(0);
	tm *ltm = localtime(&now);

	return ltm->tm_yday;
}

/************************************************************************
*                                                                       *
*  Return current Vana'diel time                                        *
*                                                                       *
************************************************************************/

uint32 CVanaTime::getVanaTime()
{
    //if custom offset is re-implemented here is the place to put it
    //all functions/variables for in game time should be derived from this
    return (uint32)time(NULL) - VTIME_BASEDATE;
    //return getSysTime() - 1009810800;
}

/************************************************************************
*                                                                       *
*  Return custom offset for real time to Vana'diel time                 *
*                                                                       *
************************************************************************/

int32 CVanaTime::getCustomOffset()
{
	return m_customOffset;
}

/************************************************************************
*                                                                       *
*  Set the real time to Vana'diel time                                  *
*                                                                       *
************************************************************************/

void CVanaTime::setCustomOffset(int32 offset)
{
	m_customOffset = offset;
	//m_TimeType = SyncTime();

	SyncTime();

	if (m_vHour >= 20)      m_TimeType = TIME_NIGHT;
	else if (m_vHour >= 18) m_TimeType = TIME_EVENING;
	else if (m_vHour >= 17) m_TimeType = TIME_DUSK;
	else if (m_vHour >=  7) m_TimeType = TIME_DAY;
	else if (m_vHour >=  6) m_TimeType = TIME_DAWN;
	else if (m_vHour >=  4) m_TimeType = TIME_NEWDAY;
}

/************************************************************************
*                                                                       *
*  Return current time type                                             *
*                                                                       *
************************************************************************/

TIMETYPE CVanaTime::GetCurrentTOTD()
{
	return m_TimeType;
}

/************************************************************************
*                                                                       *
*  Return current phase of the moon                                     *
*                                                                       *
************************************************************************/

uint32 CVanaTime::getMoonPhase()
{
	int32 phase = 0;
	//uint32 rawtime = this->getSysTime();

	//int32  game_days = (int32)(rawtime - VTIME_BASEDATE) / 3456;
	//double daysmod   = (int32)(game_days - 22) % 84;

	double daysmod = (int32)(((m_vanaDate / VTIME_DAY) + 26) % 84);

	if (daysmod >= 42)
	{
		phase = (int32)(100 * ((daysmod - 42) / 42) + 0.5);
	}
	else
	{
		phase = (int32)(100 * (1 - (daysmod / 42)) + 0.5);
	}

	return phase;
}

/************************************************************************
*                                                                       *
*  Return current moon direction                                        *
*                                                                       *
************************************************************************/

uint8 CVanaTime::getMoonDirection()
{
	//int32  phase = 0;
	//uint32 rawtime = this->getSysTime();

	//int32  game_days = (int32)(rawtime - VTIME_BASEDATE) / 3456;
	//double daysmod   = (int32)(game_days - 22) % 84;

	double daysmod = (int32)(((m_vanaDate / VTIME_DAY) + 26) % 84);

	if (daysmod == 42 || daysmod == 0)
	{
		return 0; // Neither waxing nor waning
	}
	else if (daysmod < 42)
	{
		return 1;	// Waning
	}
	else 
	{
		return 2;   // Waxing
	}
}

/************************************************************************
*                                                                       *
*                                                                       *
*                                                                       *
************************************************************************/

uint8 CVanaTime::getRSERace()
{
	return (uint8)(((m_vanaDate / VTIME_WEEK) - 22) % 8) + 1;
}

/************************************************************************
*                                                                       *
*                                                                       *
*                                                                       *
************************************************************************/

uint8 CVanaTime::getRSELocation()
{
	return (uint8)(((m_vanaDate / VTIME_WEEK) - 21) % 3);
}

/************************************************************************
*                                                                       *
*  Sync real time to Vana'diel time                                     *
*                                                                       *
************************************************************************/

TIMETYPE CVanaTime::SyncTime()
{
	//timeb SysTime;
	//ftime(&SysTime);

	// Convert real time into Vana minutes

	//m_vanaDate  = (uint32)((SysTime.time + 92514960 ) / 60.0 * 25 );

	m_vanaDate  = (uint32)(this->getVanaTime() / 60.0 * 25) + 886 * VTIME_YEAR; //convert vana time (from SE epoch in earth seconds) to vanadiel minutes and add 886 vana years

	m_vYear = (uint32)( m_vanaDate / VTIME_YEAR);
	m_vMon  = (uint32)((m_vanaDate / VTIME_MONTH) % 12) + 1;
	m_vDate = (uint32)((m_vanaDate / VTIME_DAY) % 30 ) + 1;
	m_vDay  = (uint32)((m_vanaDate % VTIME_WEEK)  / VTIME_DAY);
	m_vHour = (uint32)((m_vanaDate % VTIME_DAY)   / VTIME_HOUR);
	m_vMin  = (uint32)( m_vanaDate % VTIME_HOUR);

	if (m_vMin == 0)
	{
		switch (m_vHour)
		{
            // FOG и MIDNIGHT являются TIME_NIGHT (это не ошибка)
            // FOG and MIDNIGHT are TIME_NIGHT (this is not an error)

            case  0: m_TimeType = TIME_NIGHT;   return TIME_MIDNIGHT;
            case  2: m_TimeType = TIME_NIGHT;   return TIME_FOG;
			case  4: m_TimeType = TIME_NEWDAY;	return TIME_NEWDAY;
			case  6: m_TimeType = TIME_DAWN;	return TIME_DAWN;
			case  7: m_TimeType = TIME_DAY;		return TIME_DAY;
			case 17: m_TimeType = TIME_DUSK;	return TIME_DUSK;
			case 18: m_TimeType = TIME_EVENING; return TIME_EVENING;
			case 20: m_TimeType = TIME_NIGHT;	return TIME_NIGHT;
		}
	}
	return TIME_NONE;
}